查看原文
其他

Android逆向基础(DEX/ELF文件格式)

哆啦安全 2022-11-13

The following article is from 编码安全 Author 编码安全



背景

android逆向分析、脱壳破解分析过程中免不了和android的各种文件格式打交道(so、dex、xml、art、oat等等)。Android下的两个最重要的文件是DEX文件和SO文件,下面重点对这两个文件及关联文件进行下文的梳理总结,以此用于温故知新。



DEX文件

DEX它是android虚拟机的可执行字节码文件,我们知道java文件需要经过javac编译成class文件,dx工具会将所有的class文件合并处理最终生成dex文件。


dex文件分为四大部分: DEX文件头,索引结构区,data数据区,静态链接数据区。


在dex文件中所有的代码和数据都放在data数据区中,索引结构区中存放的是data中各种数据的对应的偏移和索引。




ODEX文件

ODEX它的英文全称为Optimized DEX;即优化过的DEX。

在android5.0之前,Android采用的是JIT(just-in-time)即时编译,也就是程序边执行边编译。为了增加程序执行的效率,android在APK第一次安装的时候将程序的dex文件进行优化生成odex文件,并将其放在了/data/dalvik-cache目录下,等待下次apk运行时直接加载这个目录中经过优化的odex文件(优化基于当前系统的dalvik虚拟机版本,不同版本上的odex文件无法进行兼容),避免重复验证提高执行效率,加快APK的响应时间。



OAT文件

在android5.0之后,android使用的是AOT(Ahead-of-time)事前编译,也就是程序在运行前先编译。oat是ART虚拟机运行的文件,是ELF格式二进制文件,包含DEX和编译的本地机器指令,oat文件包含DEX文件,因此比ODEX文件占用空间更大。


程序在首次安装的时候,dex2oat默认会把classes.dex翻译成本地机器指令,生成ELF格式的OAT文件,并将其放在了/data/dalvik-cache或者是/data/app/packagename/目录下。ART加载OAT文件后不需要经过处理就可以直接运行,它在编译时就从字节码装换成机器码了,因此运行速度更快。


在android5.0之后oat文件的后缀还是odex,但是已经不是android5.0之前的文件格式,而是ELF格式封装的本地机器码,可以认为oat在dex上加了一层壳,可以从oat里提取出dex。


(elf格式的oat)


因为此时的oat文件是一个标准的elf文件,识别其实其是不是oat文件的标准就是看其符号表。

oatdata指向的是ELF文件的.rodata节区,存放了OAT文件头OATHeader,OAT的DEX文件头,原始DEX文件的DexFile等信息。


oatexec指向的是ELF文件的.text节区,这里存放的是编译生成的指定平台的二进制代码。


oatlastword指向的是对应oat文件的结尾。


OAT文件大小差不多= dex文件+art文件



vdex文件

android8.0(Android O)之前dex文件嵌入到oat文件本身中,在Android 8.0之后dex2oat将classes.dex优化生成两个文件oat文件(.odex)和vdex文件(.vdex),其中包含APK的未压缩DEX代码,以及一些旨在加快验证速度的元数据。


odex文件中包含了本机代码的OAT

vdex文件包含了原始的DEX文件副本



ART文件

ART虚拟机在执行dex文件时,需要将dex文件中使用的类,字符串等信息转换为自定义的结构。art文件就是保存APK中使用的一些类,字符串等信息的ART内部表示,可以加快APK程序启动的速度。



ELF文件

ELF文件格式提供了两种不同的视,在汇编器和链接器看来,ELF文件是由Section Header Table描述的一系列Section的集合,而执行一个ELF文件时,在加载器(Loader)看来它是由Program Header Table描述的一系列Segment的集合。


ELF它是 Executable and Linking Format 的缩写,它是android平台上通用的二进制文件格式。在 Android 的 NDK 开发中,几乎都是和 ELF 打交道。

比如:

1、c / c++ 文件编译得到的 .o(或者 .obj)文件就是 ELF 格式的文件;

2、动态库(.so)文件、可执行文件也是 ELF 文件;

3、动态库的字符串擦除、动态库加壳、动态库修复等都离不开 ELF;


ELF文件名称中的Executable和 Linking表明 ELF 有两种重要的特性。

1、Executable表示可执行的。ELF 文件将参与程序的执行(Execution)过程。包括二进制程序的运行以及动态库 .so 文件的加载。

2、Linking表示可连接的。ELF 文件参与编译链接过程。



文件加载

Android中Java层通过System.load或System.loadLibrary来加载一个so文件,它的定义在Android源码中的路径

为/libcore/luni/src/main/java/java/lang/System.java,执行流程如下:


加载so的两种方式

1、System.loadLibrary(path),只能加载jniLIbs目录下的so文件,这个的执行流程

    1.1、先读取so文件的.init_array段

    1.2、执行JNI_OnLoad函数

    1.3、JNI_ONLoad是.so文件的初始函数

    1.4、最后调用具体的native方法


2、System.load(path),可以加载任意路径下的so


这两种方式最终都会调用Android底层的dlopen来打开so


dlopen用来打开一个动态链接库,并将其装入内存。它的定义在Android源码中的路径为/bionic/linker/dlfcn.cpp,执行流程如下:


So文件的入口为init_array、init_func这些初始化函数。这部分在dlopen的过程中就会执行,再之后的是JNI_Onload方法的调用。这里面可以注册一些本地方法,也可以继续做些变量的初始化等操作。



推荐阅读

ARM64逆向基础

ELF加壳原理与实现

浅谈加解密技术原理

Android防逆向基础

安卓逆向之ARM汇编基础

Android逆向之分析基础

安卓逆向之常用加密算法

IDA静态动态逆向分析基础

Android逆向分析基础(一)

Android逆向分析基础(二)

Android安全之ELF文件格式浅析

Android安全之DEX文件格式浅析

Android ndk开发/逆向之so文件格式基础



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存